package com.demo.webflux.spring5core.framework.aop.intercept;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.demo.webflux.spring5core.framework.aop.aspect.JoinPoint;

/**执行拦截器链，相当于spring的ReflectiveMethodInvocation
 * @author zhangsulei
 *
 */
public class MethodInvocation implements JoinPoint {

	private Object proxy; // 代理对象
	private Method method; // 代理的目标方法
	private Object target; // 代理的目标对象
	private Class<?> targetClass; // 代理的目标类
	private Object[] arguments; // 代理的方法的实参列表
	private List<Object> interceptorsAndDynamicMethodMatchers; // 回调方法链
	private Map<String, Object> userAttributes; // 保存自定义属性

	private int currentInterceptorIndex = -1;

	public MethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
		this.proxy = proxy;
		this.target = target;
		this.method = method;
		this.arguments = arguments;
		this.targetClass = targetClass;
		this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
	}

	public Object process() throws Throwable {
		// 如果interceptor执行完了，则执行JoinPoint
		if(currentInterceptorIndex == interceptorsAndDynamicMethodMatchers.size() - 1) {
			return method.invoke(target, arguments);
		}
		Object interceptorOrInterceptionAdvice = interceptorsAndDynamicMethodMatchers.get(++currentInterceptorIndex);
		// 如果要动态匹配joinPoint
		if(interceptorOrInterceptionAdvice instanceof MethodInterceptor) {
			MethodInterceptor mi = (MethodInterceptor)interceptorOrInterceptionAdvice;
			return mi.invoke(this);
		}else {
			// 执行当前interceptor
			return process();
		}
	}

	@Override
	public Method getMethod() {
		return method;
	}

	@Override
	public Object[] getArguments() {
		return arguments;
	}

	@Override
	public Object getThis() {
		return target;
	}

	@Override
	public void setUserAttribute(String key, Object value) {
		if(value != null) {
			if(userAttributes == null) {
				userAttributes = new HashMap<>();
			}
			userAttributes.put(key, value);
		}else {
			if(userAttributes != null) {
				userAttributes.remove(key);
			}
		}
	}

	@Override
	public Object getUserAttribute(String key) {
		return userAttributes != null ? userAttributes.get(key) : null;
	}

}
